package rtda

import (
	"jvm/rtda/heap"
	. "jvm/typedef"
	"jvm/util/stack"
	"math"
)

type vmStack struct {
	stack.Stack
}

func NewVMStack(capacity U4) *vmStack {
	stack := &vmStack{
		Stack: *stack.NewStack(capacity),
	}
	return stack
}
func (self *vmStack) Push(frame *Frame) {
	self.Stack.Push(frame)
}
func (self *vmStack) Pop() *Frame {
	frame := self.Stack.Pop().(*Frame)
	return frame
}
func (self *vmStack) Top() *Frame {
	frame := self.Stack.Top().(*Frame)
	return frame
}

// **************************************************
type OPStack struct {
	slots []Slot
	size  U2
}

func newOPStack(capacity U2) *OPStack {
	stack := &OPStack{
		slots: make([]Slot, capacity),
		size:  0,
	}
	return stack
}

// ***************************************************
func (self *OPStack) PushInt(val I4) {
	index := self.size
	self.size++
	self.slots[index].num = U4(val)
}
func (self *OPStack) PopInt() I4 {
	index := self.size - 1
	self.size--
	val := self.slots[index].num
	return I4(val)
}

// ***************************************************
// 大端
func (self *OPStack) PushLong(val I8) {
	index := self.size
	self.size++
	u64 := U8(val)
	high := U4(u64 >> 32)
	low := U4(u64)
	self.slots[index].num = high
	index = self.size
	self.size++
	self.slots[index].num = low
}
func (self *OPStack) PopLong() I8 {
	self.size--
	index := self.size
	low := self.slots[index].num
	self.size--
	index = self.size
	high := self.slots[index].num
	val := (U8(high) << 32) | U8(low)
	return I8(val)
}

// ***************************************************
func (self *OPStack) PushFloat(val F4) {
	bits := U4(math.Float32bits(float32(val)))
	index := self.size
	self.size++
	self.slots[index].num = bits
}
func (self *OPStack) PopFloat() F4 {
	self.size--
	index := self.size
	val := math.Float32frombits(uint32(self.slots[index].num))
	return F4(val)

}

// ***************************************************
// 大端
func (self *OPStack) PushDouble(val F8) {
	bits := math.Float64bits(float64(val))
	self.PushLong(I8(bits))
}
func (self *OPStack) PopDouble() F8 {
	bits := self.PopLong()
	val := math.Float64frombits(uint64(bits))
	return F8(val)
}

// ***************************************************
func (self *OPStack) PushRef(ref *heap.Object) {
	index := self.size
	self.size++
	self.slots[index].ref = ref
}
func (self *OPStack) PopRef() *heap.Object {
	self.size--
	index := self.size
	return self.slots[index].ref
}

// ***************************************************
func (self *OPStack) PushSlot(slot Slot) {
	index := self.size
	self.size++
	self.slots[index] = slot
}
func (self *OPStack) PopSlot() Slot {
	self.size--
	index := self.size
	return self.slots[index]
}
